﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using AutoMapper;
using Sautom.DataAccess.Helpers.Templates;
using Sautom.Domain.Entities;
using Sautom.Queries;
using Sautom.Queries.ReadOptimizedDto;
using LinqKit;

namespace Sautom.DataAccess.Queries
{
    public sealed class ClientFinder : FinderBase, IClientFinder
    {
        #region Constructors
        public ClientFinder()
            : base()
        {
        }
        #endregion

        public ICollection<ClientItemDto> GetAllClients(string personalNumberFilter, string nameRuFilter, string courseNameFilter)
        {
            //Mapper.CreateMap<Client, ClientItemDto>()
            //    .ForMember(foo => foo.OrdersCount, foo => foo.MapFrom(bar => bar.Orders.Count))
            //    .ForMember(foo => foo.IsActiveClient, foo => foo.MapFrom(bar => bar.Orders.Any(ord => ord.IsActive)))
            //    .ForMember(foo => foo.SchoolName,
            //               foo =>
            //               foo.MapFrom(
            //                   bar =>
            //                   bar.Orders.Any(ord => ord.IsActive)
            //                       ? bar.Orders.First(ord => ord.IsActive).Proposal.SchoolName
            //                       : String.Empty))
            //    .ForMember(foo => foo.CourseName,
            //               foo =>
            //               foo.MapFrom(
            //                   bar =>
            //                   bar.Orders.Any(ord => ord.IsActive)
            //                       ? bar.Orders.First(ord => ord.IsActive).Proposal.CourseName
            //                       : String.Empty))
            //    .ForMember(foo => foo.StartDate,
            //               foo =>
            //               foo.MapFrom(
            //                   bar =>
            //                   bar.Orders.Any(ord => ord.IsActive)
            //                       ? bar.Orders.First(ord => ord.IsActive).StartDate
            //                       : default(DateTime)))
            //    .ForMember(foo => foo.NameRu,
            //               foo => foo.ResolveUsing(bar => bar.LastName + " " + bar.FirstName + " " + bar.MiddleName));

            //todo make generic!

            Expression<Func<ClientItemDto, bool>> where = PredicateBuilder.True<ClientItemDto>();

            if (!string.IsNullOrWhiteSpace(personalNumberFilter))
            {
                where = where.And(rec => rec.PersonalNumber.Contains(personalNumberFilter));
            }

            if (!string.IsNullOrWhiteSpace(nameRuFilter))
            {
                where = where.And(rec => rec.NameRu.Contains(nameRuFilter));
            }

            if (!string.IsNullOrWhiteSpace(courseNameFilter))
            {
                where = where.And(rec => rec.CourseName.Contains(courseNameFilter));
            }

            var clients = DatabaseContext.Clients.Select(rec => new ClientItemDto()
                                                                    {
                                                                        Id = rec.Id,
                                                                        CourseName = rec.Orders.Any(ord => ord.StartDate > DateTime.Now) ? rec.Orders.FirstOrDefault(ord => ord.StartDate > DateTime.Now).Proposal.CourseName : String.Empty,
                                                                        StartDate = rec.Orders.Any(ord => ord.StartDate > DateTime.Now) ? rec.Orders.FirstOrDefault(ord => ord.StartDate > DateTime.Now).StartDate : default(DateTime),
                                                                        NameRu = rec.LastName + " " + rec.FirstName + " " + rec.MiddleName,
                                                                        SchoolName = rec.Orders.Any(ord => ord.StartDate > DateTime.Now) ? rec.Orders.FirstOrDefault(ord => ord.StartDate > DateTime.Now).Proposal.SchoolName : String.Empty,
                                                                        IsActiveClient = rec.Orders.Any(ord => ord.StartDate > DateTime.Now),
                                                                        OrdersCount = rec.Orders.Count,
                                                                        NameLat = rec.NameLat,
                                                                        PersonalNumber = rec.PersonalNumber
                                                                    }).AsExpandable().Where(where).ToList();

            var clientDtos = clients;//Mapper.Map<ICollection<ClientItemDto>>(clients);

            return clientDtos;
        }

        public ClientEditDto GetClientForEdit(Guid clientId)
        {
            Mapper.CreateMap<Client, ClientEditDto>()
                .ForMember(foo => foo.ParentName, foo => foo.MapFrom(bar => bar.Parent.Name))
                .ForMember(foo => foo.ParentAddress, foo => foo.MapFrom(bar => bar.Parent.Address))
                .ForMember(foo => foo.ParentPhone, foo => foo.MapFrom(bar => bar.Parent.Phone))
                .ForMember(foo => foo.ParentPassportInfo, foo => foo.MapFrom(bar => bar.Parent.PassportInfo));

            var client = DatabaseContext.Clients.FirstOrDefault(rec => rec.Id == clientId);
            return Mapper.Map<ClientEditDto>(client);
        }

        public ClientViewDto GetClientForView(Guid clientId)
        {
            Mapper.CreateMap<Client, ClientViewDto>()
                .ForMember(foo => foo.ParentName, foo => foo.MapFrom(bar => bar.Parent.Name))
                .ForMember(foo => foo.ParentAddress, foo => foo.MapFrom(bar => bar.Parent.Address))
                .ForMember(foo => foo.ParentPhone, foo => foo.MapFrom(bar => bar.Parent.Phone))
                .ForMember(foo => foo.ParentPassportInfo, foo => foo.MapFrom(bar => bar.Parent.PassportInfo))
                .ForMember(foo => foo.Orders, foo => foo.ResolveUsing(bar => bar.Orders.Where(rec => rec.EndDate.Date >= DateTime.Now.Date).ToList()));

            Mapper.CreateMap<Order, OrderItemDto>()
                .ForMember(foo => foo.SchoolName, foo => foo.MapFrom(bar => bar.Proposal.SchoolName))
                .ForMember(foo => foo.CourseName, foo => foo.MapFrom(bar => bar.Proposal.CourseName))
                .ForMember(foo => foo.IsGroupType, foo => foo.MapFrom(bar => bar.Proposal.IsGroupType))
                .ForMember(foo => foo.ResponsibleManager, foo => foo.MapFrom(bar => bar.ResponsibleManager.DisplayName))
                .ForMember(foo => foo.Intensity, foo => foo.MapFrom(bar => bar.Intensity.IntensityName))
                .ForMember(foo => foo.HouseType, foo => foo.MapFrom(bar => bar.HouseType.HousingName))
                .ForMember(foo => foo.Docs, foo =>
                    foo.ResolveUsing(bar => bar.EmbassyDocuments.Select(rec => rec.Id)))
                .ForMember(foo => foo.FullDocsList, foo => foo.Ignore());

            Mapper.CreateMap<ManagerComment, ManagerCommentItemDto>()
                .ForMember(foo => foo.Manager, foo => foo.ResolveUsing(bar => bar.Manager.DisplayName));

            Mapper.CreateMap<AirlineTicket, AirlineTicketViewDto>();

            var client = DatabaseContext.Clients.FirstOrDefault(rec => rec.Id == clientId);

            var dto = Mapper.Map<ClientViewDto>(client);
            foreach (var order in dto.Orders)
            {
                var clientOrder = client.Orders.First(rec => rec.Id == order.Id);

                order.FullDocsList = DatabaseContext.EmbassyDocuments
                    .Where(rec => rec.Country.Id == clientOrder.Proposal.City.Country.Id && !rec.IsArchival)
                    .Select(rec => new GuidStringDto() { Id = rec.Id, Element = rec.DocumentName }).ToList();

                var airTicket = DatabaseContext.AirlineTickets.FirstOrDefault(rec => rec.Order.Id == clientOrder.Id);
                order.AirlineTicket = Mapper.Map<AirlineTicketViewDto>(airTicket);
            }

            return dto;
        }

        public CreateOrderInfoDto GetOrderCreationData()
        {
            Mapper.CreateMap<Proposal, ProposalDto>()
                .ForMember(d => d.City, o => o.ResolveUsing(v => v.City.CityName))
                .ForMember(d => d.Country, o => o.ResolveUsing(v => v.City.Country.CountryName))
                .ForMember(d => d.Intensities, o => o.MapFrom(v => v.AvailableIntensities))
                .ForMember(d => d.HouseTypes, o => o.MapFrom(v => v.AvailableHouseTypes));
            Mapper.CreateMap<IntensityType, GuidStringDto>()
                .ForMember(d => d.Element, o => o.MapFrom(v => v.IntensityName))
                .ForMember(d => d.Id, o => o.MapFrom(v => v.Id));
            Mapper.CreateMap<HousingType, GuidStringDto>()
                .ForMember(d => d.Element, o => o.MapFrom(v => v.HousingName))
                .ForMember(d => d.Id, o => o.MapFrom(v => v.Id));
            Mapper.CreateMap<Manager, ManagerDto>();

            var proposals =
                DatabaseContext.Proposals.ToList();

            var model = new CreateOrderInfoDto()
                       {
                           Proposals = Mapper.Map<List<ProposalDto>>(proposals),
                           ResponsibleManagers = Mapper.Map<List<ManagerDto>>(DatabaseContext.Managers.ToList()),
                       };

            return model;
        }

        public CreateOrderInfoDto GetOrderEditData(Guid orderId)
        {
            Mapper.CreateMap<Proposal, ProposalDto>()
                .ForMember(d => d.City, o => o.ResolveUsing(v => v.City.CityName))
                .ForMember(d => d.Country, o => o.ResolveUsing(v => v.City.Country.CountryName))
                .ForMember(d => d.Intensities, o => o.MapFrom(v => v.AvailableIntensities))
                .ForMember(d => d.HouseTypes, o => o.MapFrom(v => v.AvailableHouseTypes));
            Mapper.CreateMap<IntensityType, GuidStringDto>()
                .ForMember(d => d.Element, o => o.MapFrom(v => v.IntensityName))
                .ForMember(d => d.Id, o => o.MapFrom(v => v.Id));
            Mapper.CreateMap<HousingType, GuidStringDto>()
                .ForMember(d => d.Element, o => o.MapFrom(v => v.HousingName))
                .ForMember(d => d.Id, o => o.MapFrom(v => v.Id));
            Mapper.CreateMap<Manager, ManagerDto>();

            var proposal = DatabaseContext.Orders.Find(orderId).Proposal;

            var model = new CreateOrderInfoDto()
            {
                Proposals = new List<ProposalDto>() { Mapper.Map<ProposalDto>(proposal) },
                ResponsibleManagers = Mapper.Map<List<ManagerDto>>(DatabaseContext.Managers.ToList()),
            };

            return model;
        }

        public AirlineTicketViewDto AirlineTicketForView(Guid orderId)
        {
            Mapper.CreateMap<AirlineTicket, AirlineTicketViewDto>();

            var ticket = DatabaseContext.AirlineTickets.FirstOrDefault(rec => rec.Order.Id == orderId);
            var mapped = Mapper.Map<AirlineTicketViewDto>(ticket);

            return mapped;
        }

        public AirlineTicketEditDto AirlineTicketForEdit(Guid airlineTickedId)
        {
            Mapper.CreateMap<AirlineTicket, AirlineTicketEditDto>()
                .ForMember(d => d.OrderId, o => o.ResolveUsing(v => v.Order.Id));

            var ticket = DatabaseContext.AirlineTickets.FirstOrDefault(rec => rec.Id == airlineTickedId);
            var mapped = Mapper.Map<AirlineTicketEditDto>(ticket);

            return mapped;
        }

        public ContractViewDto ContractForView(Guid orderId)
        {
            Mapper.CreateMap<Contract, ContractViewDto>();

            var contract = DatabaseContext.Contracts.FirstOrDefault(rec => rec.Order.Id == orderId);
            var mapped = Mapper.Map<ContractViewDto>(contract);

            return mapped;
        }

        public ContractEditDto ContractForEdit(Guid contractId)
        {
            Mapper.CreateMap<Contract, ContractEditDto>();

            var contract = DatabaseContext.Contracts.FirstOrDefault(rec => rec.Id == contractId);
            var mapped = Mapper.Map<ContractEditDto>(contract) ?? new ContractEditDto();

            mapped.Rates = DatabaseContext.Set<Rate>().Select(rec => new RateItemDto()
            {
                Date = rec.Date,
                RateValue = rec.RateValue
            }).ToList();

            return mapped;
        }

        public FileDownloadDto ClientContract(Guid clientId, string type)
        {
            return new FileDownloadDto()
                       {
                           FileData = TemplateProcessor.Process(DatabaseContext, clientId, type)
                       };
        }
    }
}
